﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing.Drawing2D;
using System.Threading.Tasks;
using System.Threading;
using LogLib;
using IPCPhotoEditor.Common;
using KAImage.Config;
using KAImage.Algorithms;
using KAImage;

namespace IPCPhotoEditor
{
    public partial class FormLevel : Form
    {
       private ImageLevelsOption _option = null;
       public ImageLevelsOption Option
       {
           get { return _option; }
       }

       private double[] Mapping = new double[256];

       private Bitmap _sourceImage = null;

       private Bitmap _destImage = null;

       private ImageLevels[] levels = new ImageLevels[4];

       private ImageLevels theLevel = null;

       private ImageHistograms histogram = null;

        private QueueTaskManager _taskManager = new QueueTaskManager();
     
        [DefaultValue(1.0D)]
        public double MidTone
        {
            get
            {
                if (theLevel != null)
                {
                    return theLevel.Midtone;
                }
                else
                {
                    return 1.0D;
                }                
            }
            set
            {
                theLevel.Midtone = value;        
            }
        }

        private void UpdateCtrls(double value)
        {
            if (trackBar1 != null)
            {
                SetMidToneValueToTrackBar(value);
            }             
        }

        public WorkImageUpdatedEventHandler WorkImageUpdated = null;

        protected void OnWorkImageUpdated(Bitmap image)
        {
            if (WorkImageUpdated != null)
            {
                WorkImageUpdated(this, new WorkImageUpdatedEventArgs(image));
            }
        }

        public FormLevel()
        {
            _option = KAConfigs.Levels;
            CreatLevels();
            histogram = ImageHistograms.GetInstance();
            InitializeComponent();
        }

        public FormLevel(Bitmap bmp)
        {
            CreatLevels();
            histogram =  ImageHistograms.GetInstance();
            _sourceImage = bmp.Clone() as Bitmap;
            InitializeComponent();
        }

        private void InitCtrls(ImageLevelsOption option)
        {
            levels[0].Midtone = option.RGB.MidTone;
            levels[1].Midtone = option.R.MidTone;
            levels[2].Midtone = option.G.MidTone;
            levels[3].Midtone = option.B.MidTone;
            numericUpDown1.Value = (decimal)theLevel.Midtone;
        }

        private void FormLevel_Load(object sender, EventArgs e)
        {
            _taskManager.Context = SynchronizationContext.Current;
            comboBoxChannels.SelectedIndex = 0;
            DrawHistogram();
            if (_sourceImage == null)
            {
                buttonAuto.Visible = false;
                buttonSettings.Visible = false;
            }
            else
            {
                _taskManager.StartWorking();
            }
            buttonLoad.Visible = (_sourceImage != null);
            if (_option != null)
            {
                InitCtrls(_option);
            }
        }

        private void CreatLevels()
        {
            levels[0] = new ImageLevels(ColorChannel.RGB);
            levels[1] = new ImageLevels(ColorChannel.R);
            levels[2] = new ImageLevels(ColorChannel.G);
            levels[3] = new ImageLevels(ColorChannel.B);          
            theLevel = levels[0];
        }

        private void DrawCoordinateSystem()
        {
            using (Graphics g = panelLevel.CreateGraphics())
            {
                Color FColor = Color.Black;
                Color TColor = Color.White;
                Brush b = new LinearGradientBrush(panelLevel.ClientRectangle, FColor, TColor, LinearGradientMode.Horizontal);
                g.FillRectangle(b, panelLevel.ClientRectangle);
            }
        }

        private void DrawHistogram()
        {
            switch (comboBoxChannels.SelectedIndex)
            {
                case 0:
                    histogramControl1.HistogramColor = Color.FromArgb(255, 220, 220, 220);
                    histogramControl1.UpdateHistogram(histogram, ColorChannel.RGB);
                    break;
                case 1:
                    histogramControl1.HistogramColor = Color.Red;
                    histogramControl1.UpdateHistogram(histogram, ColorChannel.R);
                    break;
                case 2:
                    histogramControl1.HistogramColor = Color.Green;
                    histogramControl1.UpdateHistogram(histogram, ColorChannel.G);
                    break;
                case 3:
                    histogramControl1.HistogramColor = Color.Blue;
                    histogramControl1.UpdateHistogram(histogram, ColorChannel.B);
                    break;
                case 4:
                    histogramControl1.UpdateHistogram(histogram);
                    break;
                default:
                    break;
            }
        }

        private void DisposeImage()
        {
            if (_sourceImage != null)
            {
                _sourceImage.Dispose();
                _sourceImage = null;
            }
            if (_destImage != null)
            {
                _destImage.Dispose();
                _destImage = null;
            }
        }

        private void FormLevel_Shown(object sender, EventArgs e)
        {
            DrawCoordinateSystem();
        }

        private void trackBar1_Scroll(object sender, EventArgs e)
        {                  
            double nv = (double)GetMidToneValueFormTrackBar();
            if (nv != MidTone)
            {
                ShowUpdatedMidToneValue(false);
                OnAdjusting();     
            }
        }

        private void numericUpDown1_ValueChanged(object sender, EventArgs e)
        {                  
             double tv = (double)numericUpDown1.Value;
             if (MidTone != tv)
             {
                 ShowUpdatedMidToneValue(true);
                 OnAdjusting();
             }
        }

        private void OnAdjusting()
        {
            if (_sourceImage != null)
            {
                LevelsAction task = new LevelsAction(this, true);
                _taskManager.AddTask(task);
            }        
        }

        private void FormLevel_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (_sourceImage != null)
            {
                _taskManager.Stop(2000);
            }
            WorkImageUpdated = null;
            DisposeImage();
        }

        private void buttonCancel_Click(object sender, EventArgs e)
        {
            this.DialogResult = System.Windows.Forms.DialogResult.Cancel;
            this.Close();
        }

        private void buttonOK_Click(object sender, EventArgs e)
        {
            if (_option != null)
            {
                _option.RGB.MidTone = levels[0].Midtone;
                _option.R.MidTone = levels[1].Midtone;
                _option.G.MidTone = levels[2].Midtone;
                _option.B.MidTone = levels[3].Midtone;
                _option.Save();
            }
            this.DialogResult = System.Windows.Forms.DialogResult.OK;
            this.Close();
        }

        private void buttonAuto_Click(object sender, EventArgs e)
        {
            AutoAdjusting autoAdj = new AutoAdjusting(_sourceImage);
            if (_destImage != null)
            {
                _destImage.Dispose();
                _destImage = null;
            }
            _destImage = autoAdj.AutoLevel();
            OnWorkImageUpdated(_destImage.Clone() as Bitmap);
        }

        private void buttonSettings_Click(object sender, EventArgs e)
        {
            FormAutoAdjustOptions form = new FormAutoAdjustOptions(1);
            form.ShowDialog();
        }

        private void SetMidToneValueToTrackBar(double value)
        {
            // 期待值
            int ev = 1000;
            if (value <= 0.1)
            {
                ev = trackBar1.Maximum;
            }
            else if (value < 1)
            {
                ev = trackBar1.Maximum - (int)(1000.0 * value);
            }
            else if (value == 1.0D)
            {
                ev = 1000;
            }
            else if (value > 1.0D && value < 9.99D)
            {
                ev = 1000 - (int)(100.0 * (value - 1.0D));
            }
            else
            {
                ev = trackBar1.Minimum;
            }
            if (trackBar1.Value != ev)
            {
                trackBar1.Value = ev;
            }
        }

        private double GetMidToneValueFormTrackBar()
        {          
            double value = 1.0D;
            int cv = trackBar1.Maximum - trackBar1.Value;
            if (cv == 0 || cv < 100)
            {
                value = 0.1D;
            }          
            else if (cv <= 900)
            {
                value = Spline.ChinaRound(cv / 1000.0D, 2);
            }
            else if (cv > 900 && cv < 1899)
            {
                value = 1.0D + Spline.ChinaRound((cv - 900) / 100.0D, 2);
            }
            else
            {
                value = 9.99D;
            }           
            return value;
        }

        private void comboBoxChannels_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (comboBoxChannels.SelectedIndex < 0)
            {
                return;
            }
            theLevel = levels[comboBoxChannels.SelectedIndex];
            SetMidToneValueToTrackBar(theLevel.Midtone);
            numericUpDown1.Value = (decimal)theLevel.Midtone;
            DrawHistogram();
        }

        private void ShowUpdatedMidToneValue(bool isNumericUpDown1)
        {
            // 如果值变化是由于TrackBar拖动进度条变化引起的
            if (!isNumericUpDown1)
            {
                double nv = GetMidToneValueFormTrackBar();
                if (nv != MidTone)
                {
                    MidTone = nv;
                    if (numericUpDown1 != null && numericUpDown1.Value != (decimal)nv)
                    {
                        numericUpDown1.Value = (decimal)nv;
                    }
                }
            }
            // 如果值变化是由于数字输入框输入变化引起的
            else
            {
                double nv = (double)numericUpDown1.Value;
                double tv = GetMidToneValueFormTrackBar();
                if (MidTone != nv)
                {
                    MidTone = nv;
                    if (tv != nv)
                    {
                        SetMidToneValueToTrackBar(nv);
                    }
                }
            }
        }

        public class LevelsAction : IQueueAction
        {
            private FormLevel parent = null;

            private bool isNumericUpDown1 = false;
            
            public LevelsAction(FormLevel form, bool updatedByNumericUpDown1)
            {
                parent = form;
                isNumericUpDown1 = updatedByNumericUpDown1;
                Timestamp = DateTime.Now.Ticks;
                Timeout = 3000;
            }

            public long Timestamp
            {
                set;
                get;
            }

            public int Timeout
            {
                set;
                get;
            }

            private int selIndex = 0;

            private Bitmap _sourceImage = null;

            private Bitmap _destImage = null;

            private ImageLevels[] levels = new ImageLevels[4];

            private ImageLevels theLevel = null;

            public void OnPrepared()
            {
                _sourceImage = parent._sourceImage;
                _destImage = parent._destImage;
                levels = parent.levels;
                theLevel = parent.theLevel;
                selIndex = parent.comboBoxChannels.SelectedIndex;             
            }

            public void Execute()
            {
                if (_destImage != null)
                {
                    _destImage.Dispose();
                    _destImage = null;
                }
                _destImage = _sourceImage.Clone() as Bitmap;
                for (int i = 1; i < levels.Length; i++)
                {
                    if (selIndex != i && !levels[i].IsDefault)
                    {
                        levels[i].Adjust(_destImage);
                    }
                }
                if (selIndex == 0)
                {
                    theLevel.Adjust(_destImage);
                }
                else
                {
                    theLevel.Adjust(_destImage);
                    if (!levels[0].IsUpdated)
                    {
                        levels[0].Adjust(_destImage);
                    }
                }
            }

            public void Simulate()
            {
                
            }

            public void UpdateUI()
            {
                parent.OnWorkImageUpdated(_destImage.Clone() as Bitmap);
                parent.DrawHistogram();
            }
        }

        private void buttonSave_Click(object sender, EventArgs e)
        {
            ImageLevelsOption option = new ImageLevelsOption();
            option.RGB.MidTone = levels[0].Midtone;
            option.R.MidTone = levels[1].Midtone;
            option.G.MidTone = levels[2].Midtone;
            option.B.MidTone = levels[3].Midtone;
            option.Save();
        }

        private void buttonLoad_Click(object sender, EventArgs e)
        {
            ImageLevelsOption option = new ImageLevelsOption();
            option.Load();
            InitCtrls(option);
            OnAdjusting();
        }

    }
}
